package server.server;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.lang.Runnable;
import java.nio.charset.StandardCharsets;
import java.util.Vector;

import server.util.mod.ModManager;

import java.util.Queue;
import java.util.LinkedList;
public class Server {
    final int Port;//端口
    ServerSocket server;//监听服务器
    public final Vector<User> clientList = new Vector<>();//用户列表
    final Queue<String> msgQueue = new LinkedList<>();
    public ModManager modManager;
    volatile boolean a;//判断消息列表是否为空;

    public Server(int port, ModManager modManager) throws Exception {
        this.Port = port;
        server = new ServerSocket(Port);
        //建立连接 监听客户端
        Thread th_cl = new Thread(new clientListen());
        th_cl.start();
        this.printMsg();
        this.modManager = modManager;

        System.out.println("【服务器】 服务器已启动！");
    }

    //从queue中取出消息打印并且发送出去
    public void printMsg() {
        Thread th_recvMsg = new Thread(new printMsg_t());
        th_recvMsg.start();
    }

    //单独向某用户发送消息
    public void sendMsgTo(String msg, User user) {
        if (!msg.isEmpty()) {
            msg += '\n';
            user.recv(msg);
        }
    }

    //发送消息函数
    public synchronized void sendMsg(String msg){
        if (!msg.isEmpty()) {
            msg += '\n';
            for (User client : clientList) {
                client.recv(msg);
            }
        }
    }
    
    // 收到消息以后服务器应该做什么
    public void msgReceived(String m, User client) {
        if (modManager.received(m, this, client)) {
            if (m.charAt(0) == '/') {
                System.out.println("【服务器】 接收到来自用户【" + client.getName() + "】的指令：" + m);
                if (!modManager.execMod(m, this, client)) {
                    System.out.println("【服务器】 该指令无效！");
                    sendMsgTo("【系统消息】 该指令无效！", client);
                }
            } else {
                msgQueue.offer('【' + client.getName() + "】\n" + m);//加入消息队列
            }
        }
    }

    // 不停从客户连接处获取消息
    class SocketRecv_t implements Runnable {
        final User client;
        volatile boolean b = true;

        SocketRecv_t(User client) {

            this.client = client;
        }

        public void run() {
            while (true) {
                if (b) {
                    b = client.getSocket().isConnected() && !client.getSocket().isClosed();
                    try {
                        //System.out.println("2222");
                        //读取信息加入消息列表
                        InputStream inFromClient = client.getSocket().getInputStream();
                        DataInputStream in = new DataInputStream(inFromClient);
                        byte[] buffer = new byte[20480];
                        //消息长度
                        int rlength=in.read(buffer, 0, 20480);
                        //传输的实际byte[]
                        if (rlength <= 0) {
                            break;
                        }
                        byte[] buffer1 = new byte[rlength];
                        System.arraycopy(buffer, 0, buffer1, 0, buffer1.length);
                        String m = new String(buffer1, StandardCharsets.UTF_8).trim();

                        msgReceived(m, client);
                    } catch (IOException e) {
                        e.printStackTrace();
                        break;
                    }
                } else
                break;
            }
            //此处在列表中删除user
            if (modManager.disconnected(Server.this, client)) {
                System.out.println("【服务器】 用户【" + client.getName() + "】已断开连接！");
                clientList.remove(client);
            }
        }
    }

    //不停的监听端口
    class clientListen implements Runnable {
        public void run() {
            while (true) {
                try {
                    Socket socket = server.accept();//接受用户端
                    User u = new User(socket);
                    if (modManager.connected(Server.this, u)) {
                        clientList.add(u);//将用户加入队列

                        //开启子线程从client处获取消息
                        Thread clientRecv = new Thread(new SocketRecv_t(u));
                        clientRecv.start();
                        sendMsg("【系统消息】 " + u.getName() + "已经连接至服务器");
                        System.out.println("【服务器】 新的连接已建立");
                    }

                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    //不停从消息队列取出消息发出
    class printMsg_t implements Runnable {
        public void run() {
            while (true) {
                a = msgQueue.isEmpty();
                if(!a) {
                    String msg = msgQueue.poll();
                    if (msg != null) {
                        sendMsg(msg);
                    }
                }
            }
        }
    }
}